home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir24 / jnos110g.zip / NRCMD.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  47KB  |  1,732 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5. /* Mods by G1EMM, PA0GRI and WG7J */
  6.   
  7. #include <ctype.h>
  8. #include <time.h>
  9. #ifdef MSDOS
  10. #include <dos.h>
  11. #endif
  12. #include "global.h"
  13. #ifdef NETROM
  14. #include "mbuf.h"
  15. #include "ax25.h"
  16. #include "mailbox.h"
  17. #include "netrom.h"
  18. #include "nr4.h"
  19. #include "timer.h"
  20. #include "iface.h"
  21. #include "pktdrvr.h"
  22. #include "lapb.h"
  23. #include "cmdparse.h"
  24. #include "session.h"
  25. #include "socket.h"
  26. #include "commands.h"
  27. #include "files.h"
  28.   
  29. int G8bpq;
  30. int Nr_hidden = 1;
  31. unsigned Nr_sorttype = 1;
  32. char Nr4user[AXALEN];
  33.   
  34. char *Nr4states[] = {
  35.     "Disconnected",
  36.     "Conn Pending",
  37.     "Connected",
  38.     "Disc Pending",
  39.     "Listening"
  40. } ;
  41.   
  42. char *Nr4reasons[] = {
  43.     "Normal",
  44.     "By Peer",
  45.     "Timeout",
  46.     "Reset",
  47.     "Refused"
  48. } ;
  49. static int dobcnodes __ARGS((int argc,char *argv[],void *p));
  50. static int dobcpoll __ARGS((int argc,char *argv[],void *p));
  51. static int dointerface __ARGS((int argc,char *argv[],void *p));
  52. static int donfadd __ARGS((int argc,char *argv[],void *p));
  53. static int donfdrop __ARGS((int argc,char *argv[],void *p));
  54. static int donfdump __ARGS((void));
  55. static int donfmode __ARGS((int argc,char *argv[],void *p));
  56. static int donodefilter __ARGS((int argc,char *argv[],void *p));
  57. static int donodetimer __ARGS((int argc,char *argv[],void *p));
  58. extern int donralias __ARGS((int argc,char *argv[],void *p));
  59. static int donracktime __ARGS((int argc,char *argv[],void *p));
  60. static int donrmycall __ARGS((int argc,char *argv[],void *p));
  61. static int donrchoketime __ARGS((int argc,char *argv[],void *p));
  62. static int donrconnect __ARGS((int argc,char *argv[],void *p));
  63. static int donrirtt __ARGS((int argc,char *argv[],void *p));
  64. static int donrkick __ARGS((int argc,char *argv[],void *p));
  65. static int dorouteadd __ARGS((int argc,char *argv[],void *p));
  66. static int doroutedrop __ARGS((int argc,char *argv[],void *p));
  67. static int donrqlimit __ARGS((int argc,char *argv[],void *p));
  68. static int donrreset __ARGS((int argc,char *argv[],void *p));
  69. static int donrretries __ARGS((int argc,char *argv[],void *p));
  70. static int donrroute __ARGS((int argc,char *argv[],void *p));
  71. int donrstatus __ARGS((int argc,char *argv[],void *p));
  72. static int donrsave __ARGS((int argc,char *argv[],void *p));
  73. static int donrload __ARGS((int argc,char *argv[],void *p));
  74. static int donrttl __ARGS((int argc,char *argv[],void *p));
  75. static int donruser __ARGS((int argc,char *argv[],void *p));
  76. static int donrwindow __ARGS((int argc,char *argv[],void *p));
  77. void doobsotick __ARGS((void));
  78. static int doobsotimer __ARGS((int argc,char *argv[],void *p));
  79. static int dominquality __ARGS((int argc,char *argv[],void *p));
  80. static int donrtype __ARGS((int argc,char *argv[],void *p));
  81. static int donrpromisc __ARGS((int argc,char *argv[],void *p));
  82. static int donrderate __ARGS((int argc,char *argv[],void *p));
  83. static int doroutesort __ARGS((int argc,char *argv[],void *p));
  84. static int donrhidden __ARGS((int argc,char *argv[],void *p));
  85. static int donrg8bpq __ARGS((int argc,char *argv[],void *p));
  86. static void doallinfo __ARGS((void));
  87.   
  88. int donrneighbour __ARGS((int argc,char *argv[],void *p));
  89.   
  90. extern int donr4tdisc __ARGS((int argc,char *argv[],void *p));
  91. extern struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
  92. extern struct nr_bind *find_bind __ARGS((struct nr_bind *list,struct nrnbr_tab *np));
  93. extern void nrresetlinks(struct nrroute_tab *rp);
  94.   
  95. static struct cmds DFAR Nrcmds[] = {
  96.     "acktime",      donracktime,    0, 0,   NULLCHAR,
  97.     "alias",    donralias,  0, 0,   NULLCHAR,
  98.     "bcnodes",  dobcnodes,  0, 2,   "netrom bcnodes <iface>",
  99.     "bcpoll",   dobcpoll,   0, 2,   "netrom bcpoll <iface>",
  100. #ifdef NETROMSESSION
  101.     "connect",  donrconnect, 1024, 2,   "netrom connect <node>",
  102. #endif
  103.     "call",     donrmycall,   0, 0,   NULLCHAR,
  104.     "choketime",    donrchoketime,  0, 0,   NULLCHAR,
  105.     "derate",       donrderate,     0, 0,   NULLCHAR,
  106. #ifdef G8BPQ
  107.     "g8bpq",        donrg8bpq,      0, 0,   NULLCHAR,
  108. #endif
  109.     "hidden",   donrhidden, 0, 0,   NULLCHAR,
  110.     "interface",    dointerface,    0, 0, NULLCHAR,
  111.     "irtt",         donrirtt,       0, 0,   NULLCHAR,
  112.     "kick",         donrkick,       0, 2,   "netrom kick <&nrcb>",
  113.     "load",         donrload,       0, 0,   NULLCHAR,
  114.     "minquality",   dominquality,   0, 0,   NULLCHAR,
  115.     "neighbour",    donrneighbour,  0, 0,   NULLCHAR,
  116.     "nodefilter",   donodefilter,   0, 0,   NULLCHAR,
  117.     "nodetimer",    donodetimer,    0, 0,   NULLCHAR,
  118.     "obsotimer",    doobsotimer,    0, 0,   NULLCHAR,
  119.     "promiscuous",  donrpromisc,    0, 0,   NULLCHAR,
  120.     "qlimit",       donrqlimit,     0, 0,   NULLCHAR,
  121.     "route",    donrroute,  0, 0,   NULLCHAR,
  122.     "reset",        donrreset,      0, 2,   "netrom reset <&nrcb>",
  123.     "retries",      donrretries,    0, 0,   NULLCHAR,
  124.     "status",       donrstatus,     0, 0,   NULLCHAR,
  125.     "save",         donrsave,       0, 0,   NULLCHAR,
  126. #if defined NETROMSESSION && defined SPLITSCREEN
  127.     "split",    donrconnect, 1024, 2,   "netrom split <node>",
  128. #endif
  129.     "timertype",    donrtype,   0, 0,   NULLCHAR,
  130.     "ttl",          donrttl,        0, 0,   NULLCHAR,
  131. #ifdef NR4TDISC
  132.     "tdisc",    donr4tdisc, 0, 0,   NULLCHAR,
  133. #endif
  134.     "user",     donruser,   0, 0,   NULLCHAR,
  135.     "window",       donrwindow,     0, 0,   NULLCHAR,
  136.     NULLCHAR,
  137. } ;
  138.   
  139.   
  140. struct timer Nodetimer ; /* timer for nodes broadcasts */
  141. struct timer Obsotimer ; /* timer for aging routes */
  142.   
  143. /* Command multiplexer */
  144. int
  145. donetrom(argc,argv,p)
  146. int argc ;
  147. char *argv[] ;
  148. void *p;
  149. {
  150.     return subcmd(Nrcmds,argc,argv,p) ;
  151. }
  152.   
  153. static struct cmds Routecmds[] = {
  154.     "add",  dorouteadd,     0, 6,
  155.     "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  156.     "drop", doroutedrop, 0, 4,
  157.     "netrom route drop <destination> <neighbor> <interface>",
  158.     "info", dorouteinfo, 0, 0,
  159.     "",
  160.     "sort", doroutesort, 0, 1,
  161.     "",
  162.     NULLCHAR,
  163. } ;
  164.   
  165. /* Route command multiplexer */
  166. static int
  167. donrroute(argc, argv,p)
  168. int argc ;
  169. char *argv[] ;
  170. void *p;
  171. {
  172.     if(argc < 2) {
  173.         doroutedump() ;
  174.         return 0 ;
  175.     }
  176.     return subcmd(Routecmds,argc,argv,p) ;
  177. }
  178.   
  179. /* Code to sort Netrom node listing
  180.  * D. Crompton  2/92
  181.  * Dump a list of known netrom routes in
  182.  * sorted order determined by sort
  183.  * flag - default = sort by alias
  184.  */
  185.   
  186. int
  187. doroutedump()
  188. {
  189.     extern unsigned Nr_sorttype;
  190.     register struct nrroute_tab *rp ;
  191.     register int i,j,k, column ;
  192.     char buf[17] ;
  193.     char *cp,*temp ;
  194.   
  195.     column = 1 ;
  196.   
  197.     for(i = 0,j=0 ; i < NRNUMCHAINS ; i++)
  198.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ;j++,rp = rp->next);
  199.   
  200. #define RTSIZE 17
  201.   
  202.     if (j) {
  203.         /* Allocate maximum size */
  204.         temp = mallocw (j*RTSIZE);
  205.   
  206.         for(i = 0,j=0,k=0 ; i < NRNUMCHAINS ; i++) {
  207.             for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  208.                 if(!Nr_hidden && *rp->alias == '#')
  209.                     continue;
  210.                 if (Nr_sorttype) {
  211.                     strcpy(buf,rp->alias) ;
  212.                     /* remove trailing spaces */
  213.                     if((cp = strchr(buf,' ')) == NULLCHAR)
  214.                         cp = &buf[strlen(buf)] ;
  215.                     if(cp != buf)   /* don't include colon for null alias */
  216.                         *cp++ = ':' ;
  217.                     pax25(cp,rp->call) ;
  218.                 } else {
  219.                     pax25(buf,rp->call);
  220.                     cp=&buf[strlen(buf)];
  221.                     *cp++=':';
  222.                     strcpy(cp,rp->alias);
  223.                 }
  224.                 sprintf(&temp[k],"%-16.16s",buf);
  225.                 k+=RTSIZE;
  226.                 j++;    /* number actually shown */
  227.             }
  228.         }
  229.   
  230. #ifdef LINUX
  231.         qsort(temp,(size_t)j,RTSIZE,(int (*)__ARGS((void*,void*))) strcmp);
  232. #else
  233.         qsort(temp,(size_t)j,RTSIZE,(int (*) ()) strcmp);
  234. #endif
  235.   
  236.         for (i=0,k=0;i<j;i++,k+=RTSIZE) {
  237.             tprintf("%-16s  ",&temp[k]) ;
  238.             if(column++ == 4) {
  239.                 if(tputc('\n') == EOF) {
  240.                     free(temp);
  241.                     return 0;
  242.                 }
  243.                 column = 1 ;
  244.             }
  245.         }
  246.   
  247.         if(column != 1)
  248.             tputc('\n') ;
  249.         free(temp);
  250.     }
  251.     return 0 ;
  252. }
  253.   
  254. /* netrom Route Dump Sort - ALIAS or CALL first */
  255. static int
  256. doroutesort(argc,argv,p)
  257. int argc ;
  258. char *argv[] ;
  259. void *p ;
  260. {
  261.     extern unsigned Nr_sorttype;
  262.   
  263.     if(argc < 2) {
  264.         tprintf("Netrom Sort by %s\n", Nr_sorttype ? "Alias" : "Call" ) ;
  265.         return 0 ;
  266.     }
  267.   
  268.     switch(argv[1][0]) {
  269.         case 'A':
  270.         case 'a':
  271.             Nr_sorttype = 1 ;
  272.             break ;
  273.         case 'C':
  274.         case 'c':
  275.             Nr_sorttype = 0 ;
  276.             break ;
  277.         default:
  278.             tputs("usage: netrom sort [alias|call]\n") ;
  279.             return -1 ;
  280.     }
  281.   
  282.     return 0 ;
  283. }
  284.   
  285. /* Print detailed information on  ALL routes  (sorted) */
  286. /*  D. Crompton */
  287. static void
  288. doallinfo()
  289. {
  290.     extern unsigned Nr_sorttype;
  291.     register struct nrroute_tab *rp ;
  292.     register struct nr_bind *bp ;
  293.     register struct nrnbr_tab *np ;
  294.     char neighbor[AXBUF] ;
  295.     char buf[17];
  296.     char *cp,*temp;
  297.     int i,j,k, flow_tmp;
  298.   
  299.     flow_tmp=Current->flowmode;
  300.     Current->flowmode=1;
  301.   
  302.     for (i=0,j=0;i<NRNUMCHAINS;i++)
  303.         for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
  304.             for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,j++);
  305.   
  306. #define STRSIZE 72
  307.   
  308.     if(j) {
  309.         temp=mallocw (j*STRSIZE);
  310.   
  311.         for (i=0,k=0;i<NRNUMCHAINS;i++)
  312.             for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
  313.                 for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,k+=STRSIZE) {
  314.                     np = bp->via ;
  315.                     if (Nr_sorttype) {
  316.                         strcpy(buf,rp->alias) ;
  317.                         if((cp = strchr(buf,' ')) == NULLCHAR)
  318.                             cp = &buf[strlen(buf)] ;
  319.                         if(cp != buf)
  320.                             *cp++ = ':' ;
  321.                         pax25(cp,rp->call) ;
  322.                     } else {
  323.                         pax25(buf,rp->call);
  324.                         cp=&buf[strlen(buf)];
  325.                         *cp++=':';
  326.                         strcpy(cp,rp->alias);
  327.                     }
  328.                     /* NOTE:
  329.                      * IF you change the size of this sprintf buffer,
  330.                      * ALSO change the size of the STRSIZE define above !!!
  331.                      */
  332.                     sprintf(&temp[k],"%-16s %s %3d %3d %-8s %-9s %c %-5u",buf,
  333.                     rp->flags & G8BPQ_NODEMASK ? "(BPQ)" : "     ",
  334.                     bp->quality,bp->obsocnt,
  335.                     np->iface->name,
  336.                     pax25(neighbor,np->call),
  337.                     (bp->flags & NRB_PERMANENT ? 'P' :
  338.                     bp->flags & NRB_RECORDED ? 'R' : 'B'),bp->usage);
  339.                     if(rp->flags & G8BPQ_NODETTL) {
  340.                         sprintf(buf,"    %u\n",rp->hops);
  341.                         strcat(&temp[k],buf);
  342.                     } else
  343.                         strcat(&temp[k],"\n");
  344.                 }
  345. #ifdef LINUX
  346.         qsort(temp,(size_t)j,STRSIZE,(int (*)__ARGS((void*,void*))) strcmp);
  347. #else
  348.         qsort(temp,(size_t)j,STRSIZE,(int (*) ()) strcmp);
  349. #endif
  350.         for(i=0,k=0;i<j;i++,k+=STRSIZE)
  351.             if (tputs(&temp[k])==EOF)
  352.                 break;
  353.         free(temp);
  354.         Current->flowmode=flow_tmp;
  355.     }
  356. }
  357.   
  358. /* Find the interface, and check if it is active for netrom */
  359. struct iface *FindNrIface(char *name) {
  360.     struct iface *ifp;
  361.   
  362.     if((ifp = if_lookup(name)) == NULLIF) {
  363.         tprintf(Badinterface,name);
  364.         return NULLIF;
  365.     }
  366.     if(!(ifp->flags & IS_NR_IFACE)) {
  367.         tprintf("%s is not active for netrom\n",name);
  368.         return NULLIF;
  369.     }
  370.     return ifp;
  371. }
  372.   
  373.   
  374. /* print detailed information on an individual route
  375.  * Shows alias as well - WG7J
  376.  */
  377. int
  378. dorouteinfo(argc,argv,p)
  379. int argc ;
  380. char *argv[] ;
  381. void *p;
  382. {
  383.     char *cp;
  384.     register struct nrroute_tab *rp ;
  385.     register struct nrroute_tab *npp;
  386.     struct nr_bind *bp ;
  387.     struct nrnbr_tab *np ;
  388.     char destbuf[AXBUF];
  389.     char neighbor[AXBUF] ;
  390.     char alias[AXALEN];
  391.     char buf[AXALEN];
  392.     char nb_alias[AXALEN];
  393.     int print_header=1;
  394.     int16 rhash;
  395.   
  396.     if(argc == 1) {
  397.         doallinfo();
  398.         return 0;
  399.     }
  400.   
  401.     putalias(alias,argv[1],0);
  402.     strupr(argv[1]);    /*make sure it's upper case*/
  403.     if((rp = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  404.         /*no such call or node alias*/
  405.         tputs("no such node\n\n");
  406.         return 0;
  407.     }
  408.     /*copy the real alias*/
  409.     strcpy(buf,rp->alias) ;
  410.     if((cp = strchr(buf,' ')) != NULLCHAR)
  411.         *cp = '\0';
  412.   
  413.     for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  414.         np = bp->via ;
  415.         /* now we have to find the alias of the neighbour used
  416.          * so we can print that as well!
  417.          */
  418.         rhash = nrhash(np->call);
  419.         for(npp=Nrroute_tab[rhash];npp!=NULLNRRTAB;npp=npp->next)
  420.             if(addreq(npp->call,np->call))
  421.                 break;
  422.         /* found, now remove trailing spaces */
  423.         strcpy(nb_alias,npp->alias) ;
  424.         if((cp = strchr(nb_alias,' ')) != NULLCHAR)
  425.             *cp = '\0';
  426.         if(print_header) {
  427.             print_header = 0;
  428.             tputs("      Node     "
  429. #ifdef G8BPQ
  430.             "      "
  431. #endif
  432.             "      Neighbour"
  433. #ifdef G8BPQ
  434.             "      "
  435. #endif
  436.             "    Port   Qual Obs Type Usage"
  437. #ifdef G8BPQ
  438.             " Hops Irtt"
  439. #endif
  440.             "\n");
  441.   
  442.             tprintf("%6s:%-9s "
  443. #ifdef G8BPQ
  444.             "%s "
  445. #endif
  446.             ,buf,pax25(destbuf,rp->call)
  447. #ifdef G8BPQ
  448.             ,rp->flags & G8BPQ_NODEMASK ? "(BPQ)" : "     "
  449. #endif
  450.             );
  451.         } else
  452.             tputs("                       ");
  453.         tprintf("%6s:%-9s "
  454. #ifdef G8BPQ
  455.         "%s "
  456. #endif
  457.         "%-6s %3d  %3d  %c   %-5u",
  458.         nb_alias,pax25(neighbor,np->call),
  459. #ifdef G8BPQ
  460.         npp->flags & G8BPQ_NODEMASK ? "(BPQ)" : "     ",
  461. #endif
  462.         np->iface->name,
  463.         bp->quality,bp->obsocnt,
  464.         bp->flags & NRB_PERMANENT ? 'P' : \
  465.         (bp->flags & NRB_RECORDED ? 'R' : 'B'),bp->usage );
  466. #ifdef G8BPQ
  467.         if(npp->hops || npp->irtt) {
  468.             if(npp->hops)
  469.                 tprintf(" %3u",npp->hops);
  470.             else
  471.                 tputs(  "    ");
  472.             if(npp->irtt)
  473.                 tprintf("  %u",npp->irtt);
  474.         }
  475. #endif
  476.         tputc('\n');
  477.     }
  478.     tputc('\n');
  479.     return 0 ;
  480. }
  481.   
  482. int
  483. donrneighbour(argc,argv,p)
  484. int argc;
  485. char *argv[];
  486. void *p;
  487. {
  488.     int i,printheader=1;
  489.     struct nrnbr_tab *np;
  490.     struct nrroute_tab *rp;
  491.     struct nr_bind *bind;
  492.     int16 rhash;
  493.     int justused;
  494.     char tmp[AXBUF];
  495.     char alias[AXALEN];
  496.     char *cp;
  497.     int percentage;
  498.     int quality = 0;
  499.     int obsocnt = 0;
  500. #ifdef G8BPQ
  501.     unsigned int irtt;
  502. #endif
  503.   
  504.     for(i=0;i<NRNUMCHAINS;i++) {    /*loop through all chains of neighbours*/
  505.         for(np=Nrnbr_tab[i];np!=NULLNTAB;np=np->next) {
  506.             /* If the interface is hidden, then do not show the route */
  507. /*
  508.             if(np->iface->flags & HIDE_PORT && Curproc->input != Command->input)
  509.                 continue;
  510.  */
  511.             if(printheader) {
  512.                 tputs("Routes :\n" \
  513.                 "   Neighbour             Port  Qual Obs Dest Tries Retries Perc"
  514. #ifdef G8BPQ
  515.                 " Irtt"
  516. #endif
  517.                 "\n");
  518.                 printheader = 0;
  519.             }
  520.             /* has this one been used recently ? */
  521.             if((secclock() - np->lastsent) < 60)
  522.                 justused = 1;
  523.             else
  524.                 justused = 0;
  525.   
  526.             /* now we have to find the alias of this neighbour
  527.              * so we can print that as well!
  528.              */
  529.             rhash = nrhash(np->call);
  530.             for(rp=Nrroute_tab[rhash];rp!=NULLNRRTAB;rp=rp->next)
  531.                 if(addreq(rp->call,np->call))
  532.                     break;
  533.   
  534.             if(rp != NULLNRRTAB) {
  535.                 /* found, now remove trailing spaces */
  536.                 strcpy(alias,rp->alias) ;
  537.                 if((cp = strchr(alias,' ')) != NULLCHAR)
  538.                     *cp = '\0';
  539.                 /*find the quality for this neighbour*/
  540.                 bind = find_bind(rp->routes,np);
  541.                 if(bind) {
  542.                     quality = bind->quality;
  543.                     obsocnt = bind->obsocnt;
  544.                 } else  // should never happen !
  545.                     quality = obsocnt = 0;
  546. #ifdef G8BPQ
  547.                 irtt = rp->irtt;
  548. #endif
  549.             } else {
  550.                 strcpy(alias,"##TEMP");
  551.             }
  552.             if(np->tries)
  553.                 percentage = (int)( (((long)(np->tries)) * 100L) /
  554.                 ((long)((long)np->tries + (long)np->retries)) );
  555.             else
  556.                 percentage = 0;
  557.             /* print it all out */
  558.             tprintf("%c %6s:%-9s %s %-6s %3d %3d  %3d %-5u %-5u   %2d %%",
  559.             (justused) ? '>' : ' ',
  560.             alias,pax25(tmp,np->call),
  561.             rp->flags & G8BPQ_NODEMASK ? "(BPQ)" : "     ",
  562.             np->iface->name,
  563.             quality,obsocnt,np->refcnt,np->tries,np->retries,percentage);
  564.             if(irtt)
  565.                 tprintf(" %u\n",irtt);
  566.             else
  567.                 tputc('\n');
  568.         }
  569.     }
  570.     if(!printheader)
  571.         tputc('\n');
  572.     return 0;
  573. }
  574.   
  575. /* define the netrom call,
  576.  * this simply changes the interface linkaddress!
  577.  * but is a little easier to use...
  578.  */
  579. static int
  580. donrmycall(argc,argv,p)
  581. int argc ;
  582. char *argv[] ;
  583. void *p;
  584. {
  585.     int len;
  586.     char tmp[AXBUF];
  587.   
  588.     if(Nr_iface == NULLIF) {
  589.         tputs("Attach netrom interface first\n") ;
  590.         return 1 ;
  591.     }
  592.   
  593.     if(argc < 2) {
  594.         if (Nr_iface->hwaddr == NULLCHAR)
  595.             tputs("not set\n");
  596.         else
  597.             tprintf("%s\n",pax25(tmp,Nr_iface->hwaddr));
  598.     } else {
  599.         if( (len=strlen(argv[1])) > (AXBUF - 1)) {
  600.             tputs("too long\n");
  601.             return 1;
  602.         }
  603.         if(Nr_iface->hwaddr != NULLCHAR)
  604.             free(Nr_iface->hwaddr);
  605.         Nr_iface->hwaddr = mallocw(AXALEN);
  606.         setcall(Nr_iface->hwaddr,argv[1]);
  607. #ifdef MAILBOX
  608.         setmbnrid();
  609. #endif
  610.     }
  611.     return 0;
  612. }
  613.   
  614. /* make an interface available to net/rom */
  615. /* arguments are:
  616.  * argv[0] - "interface"
  617.  * argv[1] - "iface" , the interface name
  618.  * argv[2] - "quality", the interface broadcast quality
  619.  * argv[3] - "n" or "v", to override the default (verbose)
  620.  *            n = never broadcast verbose
  621.  *            v = always broadcast verbose
  622.  */
  623. static
  624. int
  625. dointerface(argc,argv,p)
  626. int argc ;
  627. char *argv[] ;
  628. void *p;
  629. {
  630.     struct iface *ifp ;
  631.     int i,mtu ;
  632.   
  633.     if(Nr_iface == NULLIF) {
  634.         tputs("Attach netrom interface first\n") ;
  635.         return 1 ;
  636.     }
  637.   
  638.     if(argc < 3) {
  639.         i = 0;
  640.         for(ifp=Ifaces;ifp;ifp=ifp->next) {
  641.             if(ifp->flags & IS_NR_IFACE){
  642.                 if(!i) {
  643.                     i = 1;
  644.                     tputs("Iface  Qual MinBcQual\n");
  645.                 }
  646.                 tprintf("%-6s %-3d    %d\n",
  647.                 ifp->name,ifp->quality,ifp->nr_autofloor);
  648.             }
  649.         }
  650.         return 0;
  651.     }
  652.   
  653.     if((ifp = if_lookup(argv[1])) == NULLIF){
  654.         tprintf(Badinterface,argv[1]);
  655.         return 1;
  656.     }
  657.   
  658.     if(ifp->type != CL_AX25){
  659.         tprintf("Interface %s is not NETROM compatible\n",argv[1]);
  660.         return 1;
  661.     }
  662.   
  663.     /* activate the interface */
  664.     ifp->flags |= IS_NR_IFACE;
  665.   
  666.     /* set quality */
  667.     if((ifp->quality=atoi(argv[2])) > 255) /*Maximum quality possible*/
  668.         ifp->quality = 255;
  669.     /*check to see if quality is not 0 */
  670.     if(ifp->quality <= 0)
  671.         ifp->quality = 1;
  672.   
  673.     /* Set the minimum broadcast quality */
  674.     ifp->nr_autofloor = Nr_autofloor;
  675.     if(argc > 3)
  676.         ifp->nr_autofloor = atoi(argv[3]);
  677.   
  678.     /* Check, and set the NETROM MTU - WG7J */
  679.     if((mtu = ifp->ax25->paclen - 20) < Nr_iface->mtu)
  680.         Nr_iface->mtu = mtu;
  681.   
  682.     /* Poll other nodes on this interface */
  683.     nr_bcpoll(ifp);
  684.   
  685.     return 0 ;
  686. }
  687.   
  688.   
  689. /* convert a null-terminated alias name to a blank-filled, upcased */
  690. /* version.  Return -1 on failure. */
  691. int
  692. putalias(to,from,complain)
  693. register char *to, *from ;
  694. int complain ;
  695. {
  696.     int len, i ;
  697.   
  698.     if((len = strlen(from)) > ALEN) {
  699.         if(complain)
  700.             tputs("alias too long - six characters max\n") ;
  701.         return -1 ;
  702.     }
  703.   
  704.     for(i = 0 ; i < ALEN ; i++) {
  705.         if(i < len) {
  706.             if(islower(*from))
  707.                 *to++ = toupper(*from++) ;
  708.             else
  709.                 *to++ = *from++ ;
  710.         }
  711.         else
  712.             *to++ = ' ' ;
  713.     }
  714.   
  715.     *to = '\0' ;
  716.     return 0 ;
  717. }
  718.   
  719. /* Add a route */
  720. static int
  721. dorouteadd(argc, argv,p)
  722. int argc ;
  723. char *argv[] ;
  724. void *p;
  725. {
  726.     char alias[AXALEN] ;
  727.     char dest[AXALEN] ;
  728.     unsigned quality ;
  729.     char neighbor[AXALEN] ;
  730.     struct iface *ifp;
  731.     int naddr ;
  732.   
  733.     /* format alias (putalias prints error message if necessary) */
  734.     if(putalias(alias,argv[1],1) == -1)
  735.         return -1 ;
  736.   
  737.     /* format destination callsign */
  738.     if(setcall(dest,argv[2]) == -1) {
  739.         tputs("bad destination callsign\n") ;
  740.         return -1 ;
  741.     }
  742.   
  743.     /* find interface */
  744.     if((ifp = FindNrIface(argv[3])) == NULLIF) {
  745.         return -1;
  746.     }
  747.   
  748.     /* get and check quality value */
  749.     if((quality = atoi(argv[4])) > 255) {
  750.         tputs("maximum route quality is 255\n") ;
  751.         return -1 ;
  752.     }
  753.   
  754.     /* Change from 871225 -- no digis in net/rom table */
  755.     naddr = argc - 5 ;
  756.     if(naddr > 1) {
  757.         tputs("Use the ax25 route command to specify digipeaters\n") ;
  758.         return -1 ;
  759.     }
  760.   
  761.     /* format neighbor address string */
  762.     setcall(neighbor,argv[5]) ;
  763.   
  764.     nr_routeadd(alias,dest,ifp,quality,neighbor,1,0) ;
  765.   
  766.     /* Now see if we have a route to this neighbour,
  767.      * if not add the implied route as a temporary one.
  768.      * 930527 - WG7J
  769.      */
  770.     if(find_nrroute(neighbor) == NULLNRRTAB)
  771.         nr_routeadd("##TEMP",neighbor,ifp,quality,neighbor,0,1);
  772.   
  773.     return 0;
  774. }
  775.   
  776.   
  777. /* drop a route */
  778. static int
  779. doroutedrop(argc,argv,p)
  780. int argc ;
  781. char *argv[] ;
  782. void *p;
  783. {
  784.     char dest[AXALEN], neighbor[AXALEN] ;
  785.     struct iface *ifp;
  786.   
  787.     /* format destination and neighbor callsigns */
  788.     if(setcall(dest,argv[1]) == -1) {
  789.         tputs("bad destination callsign\n") ;
  790.         return -1 ;
  791.     }
  792.     if(setcall(neighbor,argv[2]) == -1) {
  793.         tputs("bad neighbor callsign\n") ;
  794.         return -1 ;
  795.     }
  796.   
  797.     /* find interface */
  798.     if((ifp = FindNrIface(argv[3])) == NULLIF) {
  799.         return -1;
  800.     }
  801.   
  802.     return nr_routedrop(dest,neighbor,ifp) ;
  803. }
  804.   
  805. /* Broadcast nodes list on named interface. */
  806. static int
  807. dobcnodes(argc,argv,p)
  808. int argc ;
  809. char *argv[] ;
  810. void *p;
  811. {
  812.     struct iface *ifp;
  813.   
  814.     /* find interface */
  815.     if((ifp = FindNrIface(argv[1])) == NULLIF) {
  816.         return -1;
  817.     }
  818.     nr_bcnodes(ifp) ;
  819.     return 0;
  820. }
  821.   
  822. /* Poll nodes for routes on named interface. - WG7J */
  823. static int
  824. dobcpoll(argc,argv,p)
  825. int argc ;
  826. char *argv[] ;
  827. void *p;
  828. {
  829.     struct iface *ifp;
  830.   
  831.     /* find interface */
  832.     if((ifp = FindNrIface(argv[1])) == NULLIF) {
  833.         return -1;
  834.     }
  835.     nr_bcpoll(ifp) ;
  836.     return 0;
  837. }
  838.   
  839. /* Set outbound node broadcast interval */
  840. static int
  841. donodetimer(argc,argv,p)
  842. int argc;
  843. char *argv[];
  844. void *p;
  845. {
  846.     if(argc < 2){
  847.         tprintf("Nodetimer %lu/%lu seconds\n",
  848.         read_timer(&Nodetimer)/1000L,
  849.         dur_timer(&Nodetimer)/1000L);
  850.         return 0;
  851.     }
  852.     stop_timer(&Nodetimer) ;        /* in case it's already running */
  853.     Nodetimer.func = (void (*)__ARGS((void*)))donodetick;/* what to call on timeout */
  854.     Nodetimer.arg = NULLCHAR;               /* dummy value */
  855.     set_timer(&Nodetimer,atoi(argv[1])*1000L);      /* set timer duration */
  856.     start_timer(&Nodetimer);                /* and fire it up */
  857.     return 0;
  858. }
  859.   
  860. void
  861. donodetick()
  862. {
  863.     struct iface *ifp;
  864.   
  865.     for(ifp=Ifaces;ifp;ifp=ifp->next)
  866.         if(ifp->flags & IS_NR_IFACE)
  867.             nr_bcnodes(ifp) ;
  868.   
  869.     /* Restart timer */
  870.     start_timer(&Nodetimer) ;
  871. }
  872.   
  873. /* Set timer for aging routes */
  874. static int
  875. doobsotimer(argc,argv,p)
  876. int argc;
  877. char *argv[];
  878. void *p;
  879. {
  880.     if(argc < 2){
  881.         tprintf("Obsotimer %lu/%lu seconds\n",
  882.         read_timer(&Obsotimer)/1000L,
  883.         dur_timer(&Obsotimer)/1000L);
  884.         return 0;
  885.     }
  886.     stop_timer(&Obsotimer) ;        /* just in case it's already running */
  887.     Obsotimer.func = (void (*)__ARGS((void*)))doobsotick;/* what to call on timeout */
  888.     Obsotimer.arg = NULLCHAR;               /* dummy value */
  889.     set_timer(&Obsotimer,atoi(argv[1])*1000L);      /* set timer duration */
  890.     start_timer(&Obsotimer);                /* and fire it up */
  891.     return 0;
  892. }
  893.   
  894.   
  895. /* Go through the routing table, reducing the obsolescence count of
  896.  * non-permanent routes, and purging them if the count reaches 0
  897.  */
  898. void
  899. doobsotick()
  900. {
  901.     register struct nrnbr_tab *np ;
  902.     register struct nrroute_tab *rp, *rpnext ;
  903.     register struct nr_bind *bp, *bpnext ;
  904.     int i ;
  905.   
  906.     for(i = 0 ; i < NRNUMCHAINS ; i++) {
  907.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  908.             rpnext = rp->next ;     /* save in case we free this route */
  909.         /* Check all bindings for this route */
  910.             for(bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  911.                 bpnext = bp->next ;     /* in case we free this binding */
  912.                 if(bp->flags & NRB_PERMANENT)   /* don't age these */
  913.                     continue ;
  914.                 if(--bp->obsocnt == 0) {                /* time's up! */
  915.                     if(bp->next != NULLNRBIND)
  916.                         bp->next->prev = bp->prev ;
  917.                     if(bp->prev != NULLNRBIND)
  918.                         bp->prev->next = bp->next ;
  919.                     else
  920.                         rp->routes = bp->next ;
  921.                     rp->num_routes-- ;                      /* one less binding */
  922.                     np = bp->via ;                          /* find the neighbor */
  923.                     free((char *)bp) ;                              /* now we can free the bind */
  924.                     /* Check to see if we can free the neighbor */
  925.                     if(--np->refcnt == 0) {
  926.                         if(np->next != NULLNTAB)
  927.                             np->next->prev = np->prev ;
  928.                         if(np->prev != NULLNTAB)
  929.                             np->prev->next = np->next ;
  930.                         else {
  931.                             Nrnbr_tab[nrhash(np->call)] = np->next ;
  932.                         }
  933.                         free((char *)np) ;      /* free the storage */
  934.                     }
  935.                 }
  936.             }
  937.             if(rp->num_routes == 0) {               /* did we free them all? */
  938.                 if(rp->next != NULLNRRTAB)
  939.                     rp->next->prev = rp->prev ;
  940.                 if(rp->prev != NULLNRRTAB)
  941.                     rp->prev->next = rp->next ;
  942.                 else
  943.                     Nrroute_tab[i] = rp->next ;
  944.         /* No more routes left !
  945.          * We should close/reset any netrom connections
  946.          * still idling for this route ! - WG7J
  947.          */
  948.                 nrresetlinks(rp);
  949.                 free((char *)rp) ;
  950.             }
  951.         }
  952.     }
  953.   
  954.     start_timer(&Obsotimer) ;
  955. }
  956.   
  957.   
  958. static struct cmds Nfcmds[] = {
  959.     "add",  donfadd,        0, 3,
  960.     "netrom nodefilter add <neighbor> <interface> [quality]",
  961.     "drop", donfdrop,       0, 3,
  962.     "netrom nodefilter drop <neighbor> <interface>",
  963.     "mode", donfmode,       0, 0,   NULLCHAR,
  964.     NULLCHAR,       NULLFP, 0, 0,
  965.     "nodefilter subcommands: add drop mode",
  966. } ;
  967.   
  968. /* nodefilter command multiplexer */
  969. static int
  970. donodefilter(argc,argv,p)
  971. int argc ;
  972. char *argv[] ;
  973. void *p;
  974. {
  975.     if(argc < 2) {
  976.         donfdump() ;
  977.         return 0 ;
  978.     }
  979.     return subcmd(Nfcmds,argc,argv,p) ;
  980. }
  981.   
  982. /* display a list of <callsign,interface> pairs from the filter
  983.  * list.
  984.  */
  985. static int
  986. donfdump()
  987. {
  988.     int i, column = 1 ;
  989.     struct nrnf_tab *fp ;
  990.     char buf[AXBUF] ;
  991.   
  992.     for(i = 0 ; i < NRNUMCHAINS ; i++)
  993.         for(fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  994.             pax25(buf,fp->neighbor) ;
  995.             tprintf("%-7s  %-8s  %-3d   ",
  996.             buf,fp->iface->name, fp->quality) ;
  997.             if(column++ == 3) {
  998.                 if(tputc('\n') == EOF)
  999.                     return 0;
  1000.                 column = 1 ;
  1001.             }
  1002.         }
  1003.   
  1004.     if(column != 1)
  1005.         tputc('\n') ;
  1006.   
  1007.     return 0 ;
  1008. }
  1009.   
  1010. /* add an entry to the filter table */
  1011. static int
  1012. donfadd(argc,argv,p)
  1013. int argc ;
  1014. char *argv[] ;
  1015. void *p;
  1016. {
  1017.     struct iface *ifp;
  1018.     unsigned qual;
  1019.     char neighbor[AXALEN] ;
  1020.   
  1021.     /* format callsign */
  1022.     if(setcall(neighbor,argv[1]) == -1) {
  1023.         tputs("bad neighbor callsign\n") ;
  1024.         return -1 ;
  1025.     }
  1026.   
  1027.     /* find interface */
  1028.     if((ifp = FindNrIface(argv[2])) == NULLIF) {
  1029.         return -1;
  1030.     }
  1031.   
  1032.     qual = ifp->quality; /* set default quality */
  1033.   
  1034.     if(argc > 3)
  1035.         qual = atoi(argv[3]);
  1036.   
  1037.     return nr_nfadd(neighbor,ifp,qual) ;
  1038. }
  1039.   
  1040. /* drop an entry from the filter table */
  1041. static int
  1042. donfdrop(argc,argv,p)
  1043. int argc ;
  1044. char *argv[] ;
  1045. void *p;
  1046. {
  1047.     struct iface *ifp;
  1048.     char neighbor[AXALEN] ;
  1049.   
  1050.     /* format neighbor callsign */
  1051.     if(setcall(neighbor,argv[1]) == -1) {
  1052.         tputs("bad neighbor callsign\n") ;
  1053.         return -1 ;
  1054.     }
  1055.   
  1056.     /* find interface */
  1057.     if((ifp = FindNrIface(argv[2])) == NULLIF) {
  1058.         return -1;
  1059.     }
  1060.   
  1061.     return nr_nfdrop(neighbor,ifp) ;
  1062. }
  1063.   
  1064. /* nodefilter mode subcommand */
  1065. static int
  1066. donfmode(argc,argv,p)
  1067. int argc ;
  1068. char *argv[] ;
  1069. void *p;
  1070. {
  1071.     if(argc < 2) {
  1072.         tputs("filter mode is ") ;
  1073.         switch(Nr_nfmode) {
  1074.             case NRNF_NOFILTER:
  1075.                 tputs("none\n") ;
  1076.                 break ;
  1077.             case NRNF_ACCEPT:
  1078.                 tputs("accept\n") ;
  1079.                 break ;
  1080.             case NRNF_REJECT:
  1081.                 tputs("reject\n") ;
  1082.                 break ;
  1083.             default:
  1084.                 tputs("some strange, unknown value\n") ;
  1085.         }
  1086.         return 0 ;
  1087.     }
  1088.   
  1089.     switch(argv[1][0]) {
  1090.         case 'n':
  1091.         case 'N':
  1092.             Nr_nfmode = NRNF_NOFILTER ;
  1093.             break ;
  1094.         case 'a':
  1095.         case 'A':
  1096.             Nr_nfmode = NRNF_ACCEPT ;
  1097.             break ;
  1098.         case 'r':
  1099.         case 'R':
  1100.             Nr_nfmode = NRNF_REJECT ;
  1101.             break ;
  1102.         default:
  1103.             tputs("modes are: none accept reject\n") ;
  1104.             return -1 ;
  1105.     }
  1106.   
  1107.     return 0 ;
  1108. }
  1109.   
  1110. /* netrom network packet time-to-live initializer */
  1111. static int
  1112. donrttl(argc, argv,p)
  1113. int argc ;
  1114. char *argv[] ;
  1115. void *p;
  1116. {
  1117.     return setshort(&Nr_ttl,"Time to live",argc,argv);
  1118. }
  1119.   
  1120. /* show hidden (ie '#...') nodes or not */
  1121. static int
  1122. donrhidden(argc,argv,p)
  1123. int argc ;
  1124. char *argv[] ;
  1125. void *p;
  1126. {
  1127.     return setbool(&Nr_hidden,"Hidden nodes",argc,argv);
  1128. }
  1129.   
  1130. #ifdef G8BPQ
  1131. /* Emulate G8BPQ conreq/conack frames - WG7J */
  1132. static int
  1133. donrg8bpq(argc,argv,p)
  1134. int argc ;
  1135. char *argv[] ;
  1136. void *p;
  1137. {
  1138.     return setbool(&G8bpq,"G8BPQ mode",argc,argv);
  1139. }
  1140. #endif
  1141.   
  1142. /* allow automatic derating of netrom routes on link failure */
  1143. static int
  1144. donrderate(argc,argv,p)
  1145. int argc ;
  1146. char *argv[] ;
  1147. void *p;
  1148. {
  1149.     extern int Nr_derate;
  1150.   
  1151.     return setbool(&Nr_derate,"Derate flag",argc,argv);
  1152. }
  1153.   
  1154. /* promiscuous acceptance of broadcasts */
  1155. static int
  1156. donrpromisc(argc,argv,p)
  1157. int argc ;
  1158. char *argv[] ;
  1159. void *p;
  1160. {
  1161.     extern int Nr_promisc;
  1162.   
  1163.     return setbool(&Nr_promisc,"Promiscuous flag",argc,argv);
  1164. }
  1165.   
  1166. #ifdef NETROMSESSION
  1167. /* Initiate a NET/ROM transport connection */
  1168. static int
  1169. donrconnect(argc,argv,p)
  1170. int argc ;
  1171. char *argv[] ;
  1172. void *p;
  1173. {
  1174.     struct nrroute_tab *np;
  1175.     struct sockaddr_nr lsocket, fsocket;
  1176.     char alias[AXBUF];
  1177.     struct session *sp;
  1178.     int split = 0;
  1179.   
  1180.     /*Make sure this comes from console - WG7J*/
  1181.     if(Curproc->input != Command->input)
  1182.         return 0;
  1183.   
  1184. #ifdef SPLITSCREEN
  1185.     if(argv[0][0] == 's')
  1186.         split  = 1;
  1187. #endif
  1188.   
  1189.     /* Get a session descriptor */
  1190.     if((sp = newsession(argv[1],NRSESSION,split)) == NULLSESSION) {
  1191.         tputs(TooManySessions);
  1192.         return 1 ;
  1193.     }
  1194.   
  1195.     if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  1196.         tputs(Nosock);
  1197.         keywait(NULLCHAR,1);
  1198.         freesession(sp);
  1199.         return 1;
  1200.     }
  1201.   
  1202.     /* See if the requested destination is a known alias or call,
  1203.      * use it if it is.  Otherwize give an error message. - WG7J
  1204.      */
  1205.     putalias(alias,argv[1],0);
  1206.     strupr(argv[1]);    /*make sure it's upper case*/
  1207.     if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  1208.     /*no such call or node alias*/
  1209.         tputs("no such node\n\n");
  1210.         keywait(NULLCHAR,1);
  1211.         freesession(sp);
  1212.         return 1;
  1213.     }
  1214.   
  1215.     /* Setup the local side of the connection */
  1216.     lsocket.nr_family = AF_NETROM;
  1217.   
  1218.     /* Set up our local username, bind would use Mycall instead */
  1219.     memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
  1220.   
  1221.     /* Putting anything else than Nr_iface->hwaddr here will not work ! */
  1222.     memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
  1223.   
  1224.     /* Now bind the socket to this */
  1225.     bind(sp->s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  1226.   
  1227.   
  1228.     /* Set up the remote side of the connection */
  1229.     fsocket.nr_family = AF_NETROM;
  1230.     memcpy(fsocket.nr_addr.user,np->call,AXALEN);
  1231.     memcpy(fsocket.nr_addr.node,np->call,AXALEN);
  1232.     fsocket.nr_family = AF_NETROM;
  1233.   
  1234.     return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_nr));
  1235. }
  1236. #endif
  1237.   
  1238. /* Reset a net/rom connection abruptly */
  1239. static int
  1240. donrreset(argc,argv,p)
  1241. int argc;
  1242. char *argv[];
  1243. void *p;
  1244. {
  1245.     struct nr4cb *cb ;
  1246.   
  1247.     cb = MK_FP(htoi(argv[1]),8);
  1248.     if(!nr4valcb(cb)){
  1249.         tputs(Notval);
  1250.         return 1;
  1251.     }
  1252.     reset_nr4(cb);
  1253.     return 0;
  1254. }
  1255.   
  1256. /* Force retransmission on a net/rom connection */
  1257.   
  1258. static int
  1259. donrkick(argc,argv,p)
  1260. int argc;
  1261. char *argv[];
  1262. void *p;
  1263. {
  1264.     struct nr4cb *cb ;
  1265.   
  1266.     cb = MK_FP(htoi(argv[1]),8);
  1267.     if(kick_nr4(cb) == -1) {
  1268.         tputs(Notval);
  1269.         return 1;
  1270.     } else
  1271.         return 0;
  1272. }
  1273.   
  1274. /* netrom transport ACK delay timer */
  1275. static int
  1276. donracktime(argc, argv,p)
  1277. int argc ;
  1278. char *argv[] ;
  1279. void *p;
  1280. {
  1281.     return setlong(&Nr4acktime,"Ack delay time (ms)",argc,argv);
  1282. }
  1283.   
  1284. /* netrom transport choke timeout */
  1285. static int
  1286. donrchoketime(argc, argv,p)
  1287. int argc ;
  1288. char *argv[] ;
  1289. void *p;
  1290. {
  1291.     return setlong(&Nr4choketime,"Choke timeout (ms)",argc,argv);
  1292. }
  1293.   
  1294. /* netrom transport initial round trip time */
  1295.   
  1296. static int
  1297. donrirtt(argc, argv,p)
  1298. int argc ;
  1299. char *argv[] ;
  1300. void *p;
  1301. {
  1302.     return setlong(&Nr4irtt,"Initial RTT (ms)",argc,argv);
  1303. }
  1304.   
  1305. /* netrom transport receive queue length limit.  This is the */
  1306. /* threshhold at which we will CHOKE the sender. */
  1307.   
  1308. static int
  1309. donrqlimit(argc, argv,p)
  1310. int argc ;
  1311. char *argv[] ;
  1312. void *p;
  1313. {
  1314.     return setshort(&Nr4qlimit,"Queue limit (bytes)",argc,argv);
  1315. }
  1316.   
  1317. /* Display or change our NET/ROM username */
  1318. static int
  1319. donruser(argc,argv,p)
  1320. int argc;
  1321. char *argv[];
  1322. void *p;
  1323. {
  1324.     char buf[AXBUF];
  1325.   
  1326.     if(argc < 2){
  1327.         pax25(buf,Nr4user);
  1328.         tprintf("%s\n",buf);
  1329.         return 0;
  1330.     }
  1331.     if(setcall(Nr4user,argv[1]) == -1)
  1332.         return -1;
  1333.     Nr4user[ALEN] |= E;
  1334.     return 0;
  1335. }
  1336.   
  1337. /* netrom transport maximum window.  This is the largest send and */
  1338. /* receive window we may negotiate */
  1339.   
  1340. static int
  1341. donrwindow(argc, argv,p)
  1342. int argc ;
  1343. char *argv[] ;
  1344. void *p;
  1345. {
  1346.     return setshort(&Nr4window,"Window (frames)",argc,argv);
  1347. }
  1348.   
  1349. /* netrom transport maximum retries.  This is used in connect and */
  1350. /* disconnect attempts; I haven't decided what to do about actual */
  1351. /* data retries yet. */
  1352.   
  1353. static int
  1354. donrretries(argc, argv,p)
  1355. int argc ;
  1356. char *argv[] ;
  1357. void *p;
  1358. {
  1359.     return setshort(&Nr4retries,"Retry limit",argc,argv);
  1360. }
  1361.   
  1362.   
  1363. /* Display the status of NET/ROM connections */
  1364.   
  1365. int
  1366. donrstatus(argc, argv,p)
  1367. int argc ;
  1368. char *argv[] ;
  1369. void *p;
  1370. {
  1371.     int i ;
  1372.     struct nr4cb *cb ;
  1373.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  1374.   
  1375.     if(argc < 2) {
  1376. #ifdef UNIX
  1377.         tputs("&NCB     Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1378. #else
  1379.         tputs("&NCB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1380. #endif
  1381.         for(i = 0 ; i < NR4MAXCIRC ; i++) {
  1382.             if((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1383.                 continue ;
  1384.             pax25(luser,cb->local.user) ;
  1385.             pax25(ruser,cb->remote.user) ;
  1386.             pax25(node,cb->remote.node) ;
  1387. #ifdef UNIX
  1388.             if(tprintf("%8.8x   %3d %5d %5d %9s  %9s %-9s %s\n",
  1389. #else
  1390.                 if(tprintf("%4.4x   %3d %5d %5d %9s  %9s %-9s %s\n",
  1391. #endif
  1392.                     FP_SEG(cb), cb->nbuffered, len_q(cb->txq),
  1393.                     len_p(cb->rxq), luser, ruser, node,
  1394.                     Nr4states[cb->state]) == EOF)
  1395.                     break;
  1396.         }
  1397.         return 0 ;
  1398.     }
  1399.     cb = MK_FP(htoi(argv[1]),8);
  1400.     if(!nr4valcb(cb)) {
  1401.         tputs(Notval) ;
  1402.         return 1 ;
  1403.     }
  1404.     donrdump(cb) ;
  1405.     return 0 ;
  1406. }
  1407.   
  1408. /* Dump one control block */
  1409.   
  1410. void
  1411. donrdump(cb)
  1412. struct nr4cb *cb ;
  1413. {
  1414.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  1415.     unsigned seq ;
  1416.     struct nr4txbuf *b ;
  1417.     struct timer *t ;
  1418.   
  1419.     pax25(luser,cb->local.user) ;
  1420.     pax25(ruser,cb->remote.user) ;
  1421.     pax25(node,cb->remote.node) ;
  1422.   
  1423.     tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1424.     luser, cb->mynum, cb->myid, ruser, node,
  1425.     cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  1426.   
  1427.     tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1428.     cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  1429.     len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  1430.   
  1431.     tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1432.     cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  1433.     len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  1434.   
  1435.     tputs("TACK: ") ;
  1436.     if(run_timer(&cb->tack))
  1437.         tprintf("%lu", read_timer(&cb->tack)) ;
  1438.     else
  1439.         tputs("stop") ;
  1440.     tprintf("/%lu ms; ", dur_timer(&cb->tack)) ;
  1441.   
  1442.     tputs("TChoke: ") ;
  1443.     if(run_timer(&cb->tchoke))
  1444.         tprintf("%lu", read_timer(&cb->tchoke)) ;
  1445.     else
  1446.         tputs("stop") ;
  1447.     tprintf("/%lu ms; ", dur_timer(&cb->tchoke)) ;
  1448.   
  1449.     tputs("TCD: ") ;
  1450.     if(run_timer(&cb->tcd))
  1451.         tprintf("%lu", read_timer(&cb->tcd)) ;
  1452.     else
  1453. #ifndef NR4TDISC
  1454.         tputs("stop") ;
  1455.     tprintf("/%lu ms", dur_timer(&cb->tcd)) ;
  1456. #else
  1457.     tputs("stop") ;
  1458.     tprintf("/%lu ms; ", dur_timer(&cb->tcd)) ;
  1459.   
  1460.     tputs("TDisc: ") ;
  1461.     if(run_timer(&cb->tdisc))
  1462.         tprintf("%lu", (read_timer(&cb->tdisc)/1000L)) ;
  1463.     else
  1464.         tputs("stop") ;
  1465.     tprintf("/%lu", (dur_timer(&cb->tdisc)/1000L)) ;
  1466. #endif
  1467.   
  1468.     if(run_timer(&cb->tcd))
  1469.         tprintf("; Tries: %u\n", cb->cdtries) ;
  1470.     else
  1471.         tputc('\n') ;
  1472.   
  1473.     tprintf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1474.     cb->blevel, cb->srtt, cb->mdev) ;
  1475.   
  1476.     /* If we are connected and the send window is open, display */
  1477.     /* the status of all the buffers and their timers */
  1478.   
  1479.     if(cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1480.   
  1481.         tputs("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  1482.   
  1483.         for(seq = cb->ackxpected ;
  1484.             nr4between(cb->ackxpected, seq, cb->nextosend) ;
  1485.         seq = (seq + 1) & NR4SEQMASK) {
  1486.   
  1487.             b = &cb->txbufs[seq % cb->window] ;
  1488.             t = &b->tretry ;
  1489.   
  1490.             if(tprintf("            %3u   %3d  %5d  %lu/%lu\n",
  1491.                 seq, len_p(b->data), b->retries + 1,
  1492.                 read_timer(t), dur_timer(t))
  1493.                 == EOF)
  1494.                 break;
  1495.         }
  1496.   
  1497.     }
  1498.   
  1499. }
  1500.   
  1501. /* netrom timers type - linear v exponential */
  1502. static int
  1503. donrtype(argc,argv,p)
  1504. int argc ;
  1505. char *argv[] ;
  1506. void *p ;
  1507. {
  1508.     extern unsigned Nr_timertype;
  1509.   
  1510.     if(argc < 2) {
  1511.         tprintf("Netrom timer type is %s\n", Nr_timertype ? "linear" : "exponential" ) ;
  1512.         return 0 ;
  1513.     }
  1514.   
  1515.     switch(argv[1][0]) {
  1516.         case 'l':
  1517.         case 'L':
  1518.             Nr_timertype = 1 ;
  1519.             break ;
  1520.         case 'e':
  1521.         case 'E':
  1522.             Nr_timertype = 0 ;
  1523.             break ;
  1524.         default:
  1525.             tputs("use: netrom timertype [linear|exponential]\n") ;
  1526.             return -1 ;
  1527.     }
  1528.   
  1529.     return 0 ;
  1530. }
  1531.   
  1532. static int
  1533. dominquality(argc,argv,p)
  1534. int argc ;
  1535. char *argv[] ;
  1536. void *p ;
  1537. {
  1538.     unsigned val ;
  1539.     extern unsigned Nr_autofloor;
  1540.   
  1541.     if(argc < 2) {
  1542.         tprintf("%u\n", Nr_autofloor) ;
  1543.         return 0 ;
  1544.     }
  1545.   
  1546.     val = atoi(argv[1]) ;
  1547.   
  1548.     if(val == 0 || val > 255 ) {
  1549.         tputs("maximum route quality is 255\n") ;
  1550.         return 1 ;
  1551.     }
  1552.   
  1553.     Nr_autofloor = val ;
  1554.   
  1555.     return 0 ;
  1556. }
  1557.   
  1558. /* Fixed and now functional, 920317 WG7J */
  1559. int
  1560. donrload(argc,argv,p)
  1561. int argc ;
  1562. char *argv[] ;
  1563. void *p;
  1564. {
  1565.     char buff[255];
  1566.     FILE *fn;
  1567.     time_t now, prev;
  1568. #ifdef notdef
  1569.     long t1,t2;
  1570.     int j;
  1571. #endif
  1572.     int quality,obso;
  1573.     int permanent,record;
  1574.     struct iface *ifp;
  1575.     char alias[12],dest[12],iface[12],neighbor[12],type[3],*ptr;
  1576.     char destalias[ALEN+1]; /*alias in 'alias form'*/
  1577.     char destcall[AXALEN];  /*in callsign (ie shifted) form */
  1578.     char destneighbor[AXALEN];
  1579.   
  1580.     if(Nr_iface == NULLIF) {
  1581.         tputs("Attach netrom interface first\n") ;
  1582.         return 1;
  1583.     }
  1584.   
  1585.     if((fn = fopen(Netromfile,READ_TEXT)) == NULLFILE){
  1586. /*
  1587.         tputs("Can't open netrom save file!\n");
  1588. */
  1589.         return 0;
  1590.     }
  1591.   
  1592.     if(fgets(buff,sizeof(buff),fn) == NULLCHAR){ /* read the timestamp */
  1593.         fclose(fn);
  1594.         return 1;
  1595.     }
  1596.     if((strncmp(buff,"time = ",7))!= 0){
  1597. /*
  1598.         tputs("Wrong node file content\n");
  1599. */
  1600.         fclose(fn);
  1601.         return 1;
  1602.     }
  1603.     time(&now);
  1604.     sscanf(buff,"time =%ld",&prev);
  1605. /*
  1606.     tprintf("now = %ld , prev = %ld\n",now,prev);
  1607. */
  1608.     if(prev >= now){
  1609.     /*
  1610.         tputs("You traveled back in time!!\n");
  1611.     */
  1612.         fclose(fn);
  1613.         return 1;
  1614.     }
  1615. #ifdef notdef
  1616.     t1 = now - prev;
  1617.     t2 = dur_timer(&Obsotimer)/1000L;
  1618.     j = t1 / t2;            /* recalculate obsolete count */
  1619.     tprintf("%ld seconds are past ( %d obsolete scans)\n",t1,j);
  1620. #endif
  1621.   
  1622.     while(fgets(buff,sizeof(buff),fn) != NULLCHAR){
  1623.         if((ptr = strchr(buff,':')) == 0){
  1624.             sscanf(buff,"%s%s%i%i%s%s"
  1625.             ,dest,type,&quality,&obso,iface,neighbor);
  1626.             alias[0] = '\0';
  1627.         } else {
  1628.             *ptr = ' ';
  1629.             sscanf(buff,"%s%s%s%i%i%s%s"
  1630.             ,alias,dest,type,&quality,&obso,iface,neighbor);
  1631.         }
  1632.     /*Set and check calls / alias - WG7J */
  1633.         if(setcall(destcall,dest) == -1) {
  1634.         /*
  1635.         tprintf("Bad call %s\n",dest);
  1636.         */
  1637.             continue;
  1638.         }
  1639.         if(setcall(destneighbor,neighbor) == -1) {
  1640.         /*
  1641.         tprintf("Bad call %s\n",neighbor);
  1642.         */
  1643.             continue;
  1644.         }
  1645.         if(putalias(destalias,alias,1) == -1)
  1646.             continue;
  1647.   
  1648.     /* find interface */
  1649.         if((ifp = if_lookup(iface)) == NULLIF)
  1650.             continue;
  1651.   
  1652.     /* Is it a netrom interface ? */
  1653.         if(!(ifp->flags & IS_NR_IFACE))
  1654.             continue;
  1655.   
  1656.         /* get and check quality value */
  1657.         if(quality  > 255 || quality < Nr_autofloor) {
  1658.         /*
  1659.             tputs("maximum route quality is 255\n") ;
  1660.          */
  1661.             continue;
  1662.         }
  1663.     /* Check the type of route - WG7J */
  1664.         permanent = record = 0;
  1665.         if(strchr(type,'P') != NULLCHAR)
  1666.             permanent = 1;
  1667.         else {
  1668.             if(strchr(type,'R') != NULLCHAR)
  1669.                 record = 1;
  1670.         }
  1671.         nr_routeadd(destalias,destcall,ifp,quality,destneighbor, \
  1672.         permanent,record) ;
  1673.     }
  1674.     fclose(fn);
  1675.     return 0;
  1676. }
  1677.   
  1678. int
  1679. donrsave(argc,argv,p)
  1680. int argc ;
  1681. char *argv[] ;
  1682. void *p;
  1683. {
  1684.     register struct nrroute_tab *rp ;
  1685.     register struct nr_bind *bp ;
  1686.     register struct nrnbr_tab *np ;
  1687.     char neighbor[AXBUF] ;
  1688.     register int i;
  1689.     char buf[16] ;
  1690.     char *cp ;
  1691.     FILE *fn;
  1692.     time_t now;
  1693.   
  1694. #ifdef __TURBOC__
  1695.     if((fn = fopen(Netromfile,"wt+")) == NULLFILE){
  1696. #else
  1697.         if((fn = fopen(Netromfile,"w+")) == NULLFILE){
  1698. #endif
  1699.             tputs("Can't write netrom save file!\n");
  1700.             return 1;
  1701.         }
  1702.         time(&now);
  1703.         fprintf(fn,"time = %ld\n",now);
  1704.         for(i = 0 ; i < NRNUMCHAINS ; i++){
  1705.             for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
  1706.                 strcpy(buf,rp->alias) ;
  1707.             /* remove trailing spaces */
  1708.                 if((cp = strchr(buf,' ')) == NULLCHAR)
  1709.                     cp = &buf[strlen(buf)] ;
  1710.                 if(cp != buf)           /* don't include colon for null alias */
  1711.                     *cp++ = ':' ;
  1712.                 for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1713.                     pax25(cp,rp->call) ;
  1714.                     fprintf(fn,"%-16s  ",buf) ;
  1715.                     np = bp->via ;
  1716.                     if(fprintf(fn,"%1s %3d  %3d  %-8s  %s\n",
  1717.                         (bp->flags & NRB_PERMANENT ? "P" :
  1718.                         bp->flags & NRB_RECORDED ? "R" : "X"),
  1719.                         bp->quality,bp->obsocnt,
  1720.                         np->iface->name,
  1721.                         pax25(neighbor,np->call)) == EOF)
  1722.                         break;
  1723.                 }
  1724.             }
  1725.         }
  1726.         fclose(fn);
  1727.         return 0;
  1728.     }
  1729.   
  1730. #endif /* NETROM */
  1731.   
  1732.